/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			pgsxml.cc
  \date			Feb 2012
  \author		TNick

  \brief		Contains the implementation of PgsXml class


*//*


 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Please read COPYING and README files in root folder
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#include	<QDebug>
#include	<QColor>
#include	<QFile>

#include	"pgsxml.h"


/*  INCLUDES    ============================================================ */
//
//
//
//
/*  DEFINITIONS    --------------------------------------------------------- */

using namespace PgSave;

/*  DEFINITIONS    ========================================================= */
//
//
//
//
/*  DATA    ---------------------------------------------------------------- */

/*  DATA    ================================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */



/* ------------------------------------------------------------------------- */
PgsXml *		PgsXml::createFromFile		( QString s_path )
{

	/** @todo UserMsg */

	QString	s_err;
	int		i_ecol;
	int		i_eline;
	QFile file(s_path);
	QDomDocument tmp_doc;

	if ( ! file.exists( ) )
		return NULL;

	if (!file.open(QIODevice::ReadOnly))
		return NULL;

	if (!tmp_doc.setContent( &file, &s_err, &i_eline, &i_ecol ) )
	{
		file.close();
		return NULL;
	}
	file.close();

	PgsXml * p_inst = new PgsXml();
	p_inst->doc = tmp_doc;
	p_inst->crt_p_ = tmp_doc.documentElement();

	return p_inst;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
PgsXml *		PgsXml::createFromFile		(
		QString s_path, QMap<QString, KB_BLIND_LOAD> &other_map )
{
	PgsXml * p_inst = createFromFile( s_path );
	if ( p_inst == NULL )
		return NULL;
	p_inst->uniteKb( other_map );
	return p_inst;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
PgsXml *		PgsXml::createNew		( QString s_root )
{
	PgsXml * p_inst = new PgsXml();
	p_inst->crt_p_ = p_inst->doc.createElement( s_root );
	p_inst->doc.appendChild( p_inst->crt_p_ );
	return p_inst;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
PgsXml *		PgsXml::createNew		(
		QString s_root, QMap<QString, KB_BLIND_LOAD> &other_map )
{
	PgsXml * p_inst = createNew( s_root );
	if ( p_inst == NULL )
		return NULL;
	p_inst->uniteKb( other_map );
	return p_inst;
}
/* ========================================================================= */



/* ------------------------------------------------------------------------- */
PgsXml::PgsXml	( void )
#ifdef	USE_PGSAVE_INTERFACE
	:	IPgSave()
	#endif
{
	/* stub */
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
PgsXml::~PgsXml	( void )
{
	/* stub */
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::getElementByPath (
		const QDomElement & base, const QString & s_path,
		QDomElement & out_e )
{
	if ( s_path.isEmpty() )
		return false;
	if ( base.isNull() )
		return false;

	int		i;
	QStringList	sl = s_path.split( "/", QString::SkipEmptyParts );

	out_e = base;
	for ( i = 0; i < sl.count(); i++ )
	{
		out_e = out_e.firstChildElement( );
		if ( out_e.isNull() )
			return false;
	}
	return true;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::setPath			( const QString new_crt )
{

	if ( new_crt.startsWith("/") )
	{
		/* absolute path */
		crt_p_ = enshurePath( new_crt );
	}
	else
	{
		/* relative path */
		if ( crt_p_.isNull() )
		{
			crt_p_ = doc.documentElement();
		}
		crt_p_ = enshurePath( crt_p_, new_crt );
	}

	if ( crt_p_.isNull() )
	{
		crt_p_ = doc.documentElement();
		return false;
	}
	return true;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QString		PgsXml::elPath				( const QDomElement &base )
{
	QDomElement	tmpe;
	QDomNode	tmpn = base;
	QStringList sl;
	QString		s_ret;
	while ( tmpn.isNull() == false )
	{
		if ( ! tmpn.isElement() )
			break;
		tmpe = tmpn.toElement();
		sl.append( tmpe.tagName() );
		tmpn = tmpe.parentNode();
	}
	int i = sl.count() - 1;
	while ( i >= 0 )
	{
		s_ret += "/" + sl.at( i );
		i--;
	}
	return s_ret;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		PgsXml::elPath				(
		const QDomElement & base, QStringList & sl )
{
	sl.clear();

	QDomElement	tmpe;
	QDomNode	tmpn = base;
	while ( tmpn.isNull() == false )
	{
		if ( ! tmpn.isElement() )
			break;
		tmpe = tmpn.toElement();
		sl.prepend( tmpe.tagName() );
		tmpn = tmpn.parentNode();
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QString		PgsXml::path			( void )
{

	QString rel_path = elPath( crt_p_ );
	qDebug() << "1...>" << rel_path;
	Q_ASSERT( rel_path.startsWith( "/" + doc.documentElement().tagName() ) );
	rel_path = rel_path.mid( doc.documentElement().tagName().length() + 1);
	if ( rel_path.isEmpty() )
		rel_path = "/";
	qDebug() << rel_path;
	return rel_path;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		PgsXml::path			( QStringList & sl_out )
{
	QString rel_path = path();
	sl_out = rel_path.split( "/", QString::SkipEmptyParts );
	return;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		PgsXml::cdUp			( unsigned steps )
{
	QDomNode	tmpn = crt_p_.parentNode();
	if ( steps == 0 )
		return;

	while ( tmpn.isNull() == false )
	{
		if ( ! tmpn.isElement() )
			break;
		crt_p_ = tmpn.toElement();
		steps--;
		if ( steps == 0 )
			break;
		tmpn = tmpn.parentNode();
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::exists			( QString s_path )
{

	QDomElement		new_crt_p_;

	if ( s_path.startsWith("/") )
	{
		/* root path */
		if ( s_path.length() == 1 )
			return false;

		/* absolute path */
		if ( getElementByPath(
				 s_path,
				 doc.documentElement(),
				 new_crt_p_ ) )
		{
			return (new_crt_p_.childNodes().count() != 0);
		}
		return false;
	}
	else
	{
		/* path relative to current element */
		if ( getElementByPath( crt_p_, s_path, new_crt_p_) )
		{
			return true;
		}
		return false;
	}

	return false;
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
bool		PgsXml::internalBlindLoad		(
		QDomElement targ_el, KB_BLIND_LOAD kb_default, void * kb_data )
{
	QDomElement		crt_val;

	if ( targ_el.isNull() )
		return false;

	QString s_ty = targ_el.attribute( TAG_NAME_TYPE );
	if ( s_ty.isEmpty() ) return false;
	crt_val = targ_el.firstChildElement( TAG_NAME_VALUE );
	if ( crt_val.isNull() ) return false;

	KB_BLIND_LOAD kb = getKb( s_ty );
	if ( kb == NULL )
	{
		if ( kb_default != NULL )
		{
			kb_default( this, targ_el.tagName(), kb_data );
			return true;
		}
		return false;
	}
	kb( this, targ_el.tagName(), kb_data );
	return true;

}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void		PgsXml::blindLoad		( KB_BLIND_LOAD kb_default, void * kb_data )
{

	QDomElement		targ_el;

	targ_el = crt_p_.firstChildElement();
	while ( targ_el.isNull() == false )
	{
		internalBlindLoad( targ_el, kb_default, kb_data );
		targ_el = targ_el.nextSiblingElement( );
	}

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		PgsXml::blindLoad		(
		QStringList load_list, KB_BLIND_LOAD kb_default, void * kb_data )
{
	QDomElement		targ_el;

	for ( int i = 0; i < load_list.count(); i++ )
	{
		targ_el = crt_p_.firstChildElement( load_list.at( i ) );
		internalBlindLoad( targ_el, kb_default, kb_data );
	}

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QString		PgsXml::internalGetVarStr	( const QString &s_name, bool * b_ok )
{
	for (;;)	{
		QDomElement trg_el = crt_p_.firstChildElement( s_name );
		if ( trg_el.isNull() ) break;

		trg_el = trg_el.firstChildElement( TAG_NAME_VALUE );
		if ( trg_el.isNull() ) break;

		*b_ok = true;
		return trg_el.text();
	}
	*b_ok = false;
	return QString();

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::getBool		( QString s_name, bool * b_ok )
{
	QString s_cont = internalGetVarStr( s_name, b_ok )
			.trimmed().toUpper();
	if ( s_cont == PQXML_TRUE )
	{
		*b_ok = true;
		return true;
	}
	else if ( s_cont == PQXML_FALSE )
	{
		*b_ok = true;
		return false;
	}
	*b_ok = false; return 0;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
qint16		PgsXml::getShort		( QString s_name, bool * b_ok )
{
	QString s_cont = internalGetVarStr( s_name, b_ok );
	return (qint16)s_cont.toLongLong( b_ok );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
qint32		PgsXml::getInt		( QString s_name, bool * b_ok )
{
	QString s_cont = internalGetVarStr( s_name, b_ok );
	return (qint32)s_cont.toLongLong( b_ok );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
qint64		PgsXml::getLong		( QString s_name, bool * b_ok )
{
	QString s_cont = internalGetVarStr( s_name, b_ok );
	return (qint64)s_cont.toLongLong( b_ok );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
qint8		PgsXml::getByte		( QString s_name, bool * b_ok )
{
	QString s_cont = internalGetVarStr( s_name, b_ok );
	return (qint8)s_cont.toLongLong( b_ok );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QColor		PgsXml::getColor		( QString s_name, bool * b_ok )
{
	QString s_cont = internalGetVarStr( s_name, b_ok );
	QColor	col;
	col.setNamedColor( s_cont );
	return col;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
qreal		PgsXml::getDouble	( QString s_name, bool * b_ok )
{
	QString s_cont = internalGetVarStr( s_name, b_ok );
	return s_cont.toDouble( b_ok );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QStringList	PgsXml::getStrLst	( QString s_name, bool * b_ok )
{

	for (;;)	{
		QDomElement trg_el = crt_p_.firstChildElement( s_name );
		if ( trg_el.isNull() ) break;

		trg_el = trg_el.firstChildElement( TAG_NAME_VALUE );
		if ( trg_el.isNull() ) break;

		QStringList	sl;
		QDomElement itr_el = trg_el.firstChildElement( );
		while ( itr_el.isNull() )
		{
			sl.append( itr_el.text() );
			itr_el = itr_el.nextSiblingElement();
		}

		*b_ok = true;
		return sl;
	}
	*b_ok = false;
	return QStringList();

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QString		PgsXml::getStr		( QString s_name, bool * b_ok )
{
	return internalGetVarStr( s_name, b_ok );
}
/* ========================================================================= */



/* ------------------------------------------------------------------------- */
QDomElement	PgsXml::enshurePath			(
		QDomElement & base, const QString & s_name )
{
	QStringList sl = s_name.split( "/", QString::SkipEmptyParts );
	if ( sl.count() == 0)
		return QDomElement();
	return enshurePath( base, sl );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QDomElement	PgsXml::enshurePath			(
		QDomElement & base, const QStringList & s_lst )
{
	QDomElement trg_el;
	QDomElement trg_itr;

	if ( base.isNull() )
		return QDomElement();

	trg_itr = base;
	for ( int i = 0; i < s_lst.count(); i++ )
	{
		trg_el = trg_itr.firstChildElement( s_lst.at( i ) );
		if ( trg_el.isNull() )
		{
			trg_el = doc.createElement( s_lst.at( i ) );
			trg_itr.appendChild( trg_el );
		}
		trg_itr = trg_el;
	}
	return trg_itr;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QDomElement	PgsXml::enshurePath			( const QString & s_name )
{
	QStringList sl = s_name.split( "/", QString::SkipEmptyParts );
	if ( sl.count() == 0)
		return QDomElement();
	return enshurePath( sl );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QDomElement	PgsXml::enshurePath			( const QStringList & s_lst )
{
	QDomElement trg_el;
	QDomElement trg_itr;

	trg_itr = doc.documentElement();
	for ( int i = 0; i < s_lst.count(); i++ )
	{
		trg_el = trg_itr.firstChildElement( s_lst.at( i ) );
		if ( trg_el.isNull() )
		{
			trg_el = doc.createElement( s_lst.at( i ) );
			trg_itr.appendChild( trg_el );
		}
		trg_itr = trg_el;
	}
	return trg_itr;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QDomElement		PgsXml::enshureVar	(
		const QString & s_name,
		const QString & s_type,
		const QString & s_val )
{
	QDomElement trg_el;
	QDomElement trg_el_ty;
	QDomElement trg_el_val;
	QDomText	tx_el_new;

	trg_el = crt_p_.firstChildElement( s_name );
	if ( trg_el.isNull() )
	{ /* we need to create the whole shaboom */
		trg_el = doc.createElement( s_name );
		crt_p_.appendChild( trg_el );

		trg_el_ty = doc.createElement( TAG_NAME_TYPE );
		trg_el.appendChild( trg_el_ty );

		trg_el_val = doc.createElement( TAG_NAME_VALUE );
		trg_el.appendChild( trg_el_val );
	}
	else
	{
		trg_el_ty = trg_el.firstChildElement( TAG_NAME_TYPE );
		if ( trg_el_ty.isNull() )
		{
			trg_el_ty = doc.createElement( TAG_NAME_TYPE );
			trg_el.appendChild( trg_el_ty );
		}

		trg_el_val = trg_el.firstChildElement( TAG_NAME_VALUE );
		if ( trg_el_val.isNull() )
		{
			trg_el_val = doc.createElement( TAG_NAME_VALUE );
			trg_el.appendChild( trg_el_val );
		}
	}

	tx_el_new = doc.createTextNode( s_type );
	trg_el_ty.appendChild( tx_el_new );

	tx_el_new = doc.createTextNode( s_val );
	trg_el_val.appendChild( tx_el_new );

	return trg_el;
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
bool		PgsXml::set		( QString s_name, const qint64 new_val )
{
	return ( enshureVar( s_name,
						 PQXML_INT,
						 QString::number(new_val)
						 ).isNull() == false );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::set		( QString s_name, const int new_val )
{
	return ( enshureVar( s_name,
						 PQXML_INT,
						 QString::number( new_val )
						 ).isNull() == false );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::set		( QString s_name, const bool new_val )
{
	return ( enshureVar( s_name,
						 PQXML_BOOL,
						 ( new_val ? PQXML_TRUE : PQXML_FALSE )
						 ).isNull() == false );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::set		( QString s_name, const char new_val )
{
	return ( enshureVar( s_name,
						 PQXML_CHAR,
						 QString::number( new_val )
						 ).isNull() == false );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::set		( QString s_name, const QRgb new_val )
{
	return ( enshureVar( s_name,
						 PQXML_COLOR,
						 QString::number( new_val )
						 ).isNull() == false );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::set		( QString s_name, const QColor new_val )
{
	return ( enshureVar( s_name,
						 PQXML_COLOR,
						 new_val.name()
						 ).isNull() == false );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::set		( QString s_name, const QString new_val )
{
	return ( enshureVar( s_name,
						 PQXML_STR,
						 new_val
						 ).isNull() == false );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::set		( QString s_name, const char * new_val )
{
	return ( enshureVar( s_name,
						 PQXML_STR,
						 new_val
						 ).isNull() == false );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::set		( QString s_name, const qreal new_val )
{
	return ( enshureVar( s_name,
						 PQXML_DBL,
						 QString::number( new_val )
						 ).isNull() == false );
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool		PgsXml::saveToFile	( QString s_path )
{
	/** @todo	UserMsg */
	QString	s_file_cont = saveToString();
	if ( s_file_cont.isEmpty() )
		return false;

	QFile file( s_path );

	if ( ! file.open( QIODevice::WriteOnly | QIODevice::Text) )
		return false;

	QTextStream out( &file );
	out << s_file_cont;

	file.close();
	return true;
}
/* ========================================================================= */


#ifdef	PGSAVE_TESTS

#define TEST_FILE		"test.xml"

/* ------------------------------------------------------------------------- */
void				PgSave::PgsXml_Tests					(
		int & performed, int & succeded )
{
	QString Outcm;
	bool	b_ok;
	performed = 0;
	succeded = 0;

	qDebug() << "Testing IPgSave with XML implementation";

	/* ------------------------ */
	PgsXml * inst = PgsXml::createNew( "test_root" );
	TEST_RESULT( inst != NULL, " - creating a new instance" );
	if ( inst == NULL )
		return;
	IPgSave_Test_i( inst, performed, succeded );

	TEST_RESULT( inst->saveToFile( TEST_FILE ),
				 " - saving to a file" );
	delete inst;



	/* ------------------------ */
	inst = PgsXml::createFromFile( TEST_FILE );
	TEST_RESULT( inst != NULL, " - loading an existing file" );
	if ( inst == NULL )
		return;
	IPgSave_Test_j( inst, performed, succeded );


	delete inst;
	return;
}
/* ========================================================================= */
#endif


/*  CLASS    =============================================================== */
//
//
//
//
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
